#ifndef _GWBASE_BASE_ATOMIC_H_
#define _GWBASE_BASE_ATOMIC_H_

#include <stdint.h>

namespace dicom {

inline void MemoryBarrier() {
  // See http://gcc.gnu.org/ml/gcc/2003-04/msg01180.html for a discussion on
  // this idiom. Also see http://en.wikipedia.org/wiki/Memory_ordering.
  __asm__ __volatile__("" : : : "memory");
}

template <typename T>
class AtomicIntegerT {
 public:
  AtomicIntegerT() : value_(0) {}
  explicit AtomicIntegerT(T v) : value_(v) {}

  T CompareAndSwap(T old_value, T new_value) {
    return __sync_val_compare_and_swap(&value_, old_value, new_value);
  }

  T Add(T n) { return __sync_fetch_and_add(&value_, n) + n; }
  T Increment() { return Add(1); }
  T Decrement() { return Add(-1); }

  T Load_Acquire() {
    T result = value_;
    MemoryBarrier();
    return result;
  }

  void Store_Release(T v) {
    MemoryBarrier();
    value_ = v;
  }

 private:
  volatile T value_;
};

typedef AtomicIntegerT<int32_t> AtomicInt32;
typedef AtomicIntegerT<int64_t> AtomicInt64;
}

#endif /* _GWBASE_BASE_ATOMIC_H_ */
